home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 1.iso / toolbox / src / demos / OpenGL / lorenz / lorenz.c < prev    next >
C/C++ Source or Header  |  1996-11-11  |  16KB  |  632 lines

  1. /*
  2.  * Lorenz Attractor Demo
  3.  *
  4.  * Adapted from code originally written for the 4D60GT by
  5.  * Aaron T. Ferrucci (aaronf@cse.ucsc.edu), 7/3/92.
  6.  *
  7.  * Description:
  8.  *
  9.  * This program shows some particles stuck in a Lorenz attractor (the parameters
  10.  * used are r=28, b=8/3, sigma=10). The eye is attracted to the red particle,
  11.  * with a force directly proportionate to distance. A command line
  12.  * puts the whole mess inside a box made of hexagons. I think this helps to
  13.  * maintain the illusion of 3 dimensions, but it can slow things down.
  14.  * Other options allow you to play with the redraw rate and the number of new
  15.  * lines per redraw. So you can customize it to the speed of your machine.
  16.  * 
  17.  * For general info on Lorenz attractors I recommend "An Introduction to
  18.  * the Lorenz Equations", IEEE Transactions on Circuits and Systems, August '83.
  19.  *
  20.  * Bugs: hidden surface removal doesn't apply to hexagons, and
  21.  * works poorly on lines when they are too close together.
  22.  *
  23.  * Notes on OpenGL port:
  24.  * 
  25.  * The timer functions do not exist in OpenGL, so the drawing occurs in a
  26.  * continuous loop, controlled by step, stop and go input from the keyboard.
  27.  * Perhaps system function could be called to control timing.
  28.  *
  29.  */
  30.  
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include <GL/gl.h>
  35. #include <GL/glu.h>
  36. #include <math.h>
  37. #include <time.h>
  38. #include <getopt.h>
  39. #include <GL/glut.h>
  40.  
  41.  
  42. static GLuint asphere;
  43.  
  44. #define POINTMASK (unsigned long)511
  45. #define G (0.002)    /* eyept to red sphere gravity */
  46. #define LG (0.3)
  47. #define CUBESIDE (120.)
  48. #define CUBESCALE (23.)
  49. #define CUBEOFFX (-4.)
  50. #define CUBEOFFY (0.)
  51. #define CUBEOFFZ (57.)
  52. #define FALSE 0
  53. #define TRUE 1
  54.  
  55. /* globals */
  56. float sigma = 10., r = 28., b = 8./3., dt = 0.003;
  57. unsigned long rp = 0, bp = 0, gp = 0, yp = 0, mp = 0;
  58. long xmax, ymax, zmax, zmin;
  59. float rv[POINTMASK+1][3],            /* red points */
  60.     bv[POINTMASK+1][3],        /* blue points */
  61.     gv[POINTMASK+1][3],        /* green points */
  62.     yv[POINTMASK+1][3],        /* yellow points */
  63.     mv[POINTMASK+1][3];        /* magenta points */
  64.  
  65. int lpf;                /* number of new lines per frame */
  66.  
  67. float eyex[3],    /* eye location */
  68.      eyev[3],    /* eye velocity */
  69.      eyel[3];    /* lookat point location */
  70. GLint fovy = 600;
  71. float dx, dy, dz;
  72. GLUquadricObj *quadObj;
  73.  
  74. float cubeoffx = CUBEOFFX;
  75. float cubeoffy = CUBEOFFY;
  76. float cubeoffz = CUBEOFFZ;
  77. float farplane = 80.;
  78.  
  79. int animate = 1;
  80.  
  81. /* option flags */
  82. GLboolean hexflag,        /* hexagons? */
  83.     sflag,             
  84.     fflag,            
  85.     wflag,
  86.     gflag,
  87.     debug;
  88.  
  89. /* option values */
  90. short hexbright;    /* brightness for hexagon color */
  91. int speed,        /* speed (number of new line segs per redraw) */
  92.     frame;        /* frame rate (actually noise value for TIMER0) */
  93. float a = 0,
  94.     da;            /* hexagon rotational velocity (.1 degree/redraw) */
  95. float gravity;
  96.  
  97. /* function declarations */
  98. void init_3d(void);
  99. void init_graphics(void);
  100. void draw_hexcube(void);
  101. void draw_hexplane(void);
  102. void draw_hexagon(void);
  103. void move_eye(void);
  104. void redraw(void);
  105. void next_line(float v[][3], unsigned long *p);
  106. void parse_args(int argc, char **argv);
  107. void print_usage(char*);
  108. void print_info(void);
  109. void sphdraw(float args[4]);
  110. void setPerspective(int angle, float aspect, float zNear, float zFar);
  111.  
  112.  
  113. static void Reshape(int width, int height)
  114. {
  115.  
  116.       glViewport(0,0,width,height);
  117.       glClear(GL_COLOR_BUFFER_BIT);
  118.       xmax = width;
  119.       ymax = height;
  120. }
  121.  
  122. static void Key(unsigned char key, int x, int y)
  123. {
  124.  
  125.     switch (key) {
  126.       case 'g':
  127.     animate = 1;
  128.     glutPostRedisplay();
  129.     break;
  130.       case 's':
  131.      animate = 0;
  132.      glutPostRedisplay();
  133.      break;
  134.       case 27:
  135.     gluDeleteQuadric(quadObj);
  136.     exit(0);
  137.     }
  138. }
  139.  
  140. static void Draw(void)
  141. {
  142.     int i, j;
  143.  
  144.     if (animate) {
  145.     i = speed;
  146.     while (i--) {
  147.         next_line(rv, &rp);
  148.         next_line(bv, &bp);
  149.         next_line(gv, &gp);
  150.         next_line(yv, &yp);
  151.         next_line(mv, &mp);
  152.     }
  153.     glPushMatrix();
  154.     move_eye();
  155.     redraw();
  156.     glPopMatrix();
  157.     }
  158. }
  159.  
  160. void main(int argc, char **argv)
  161. {
  162.  
  163.     parse_args(argc, argv);
  164.  
  165.     glutInitWindowSize(600, 600);
  166.  
  167.     glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE);
  168.  
  169.     glutCreateWindow("Lorenz Attractors");
  170.  
  171.     init_3d();
  172.     init_graphics();
  173.  
  174.     /* draw the first POINTMASK points in each color */
  175.     while(rp < POINTMASK) {
  176.     next_line(rv, &rp);
  177.     next_line(bv, &bp);
  178.     next_line(gv, &gp);
  179.     next_line(yv, &yp);
  180.     next_line(mv, &mp);
  181.     }
  182.  
  183.     eyex[0] = eyex[1] = eyex[2] = 0.;
  184.     eyel[0] = rv[rp][0];
  185.     eyel[1] = rv[rp][1];
  186.     eyel[2] = rv[rp][2];
  187.     
  188.     glPushMatrix();
  189.     move_eye();
  190.     redraw();
  191.     glPopMatrix();
  192.  
  193.     glutReshapeFunc(Reshape);
  194.     glutKeyboardFunc(Key);
  195.     glutIdleFunc(Draw);
  196.     glutDisplayFunc(Draw);
  197.     glutMainLoop();
  198. }
  199.  
  200. /* compute the next point on the path according to Lorenz' equations. */
  201. void next_line(float v[][3], unsigned long *p)
  202. {
  203.  
  204.     dx = sigma * (v[*p][1] - v[*p][0]) * dt;
  205.     dy = (r*v[*p][0] - v[*p][1] + v[*p][0]*v[*p][2]) * dt;
  206.     dz = (v[*p][0] *v[*p][1] + b*v[*p][2]) * dt;    
  207.     
  208.     v[(*p + 1) & POINTMASK][0] = v[*p][0] + dx;
  209.     v[(*p + 1) & POINTMASK][1] = v[*p][1] + dy;
  210.     v[(*p + 1) & POINTMASK][2] = v[*p][2] - dz;
  211.     *p = (*p + 1) & POINTMASK;
  212. }
  213.  
  214. void drawLines(unsigned long index, float array[POINTMASK][3])
  215. {
  216.     unsigned long p;
  217.     int i;
  218.  
  219. #define LINE_STEP 4
  220.  
  221.     p = (index+1)&POINTMASK;
  222.     i = LINE_STEP-(p % LINE_STEP);
  223.     if (i == LINE_STEP) i=0;
  224.     glBegin(GL_LINE_STRIP);
  225.     /* draw points in order from oldest to newest */
  226.     while(p != index) {
  227.         if (i == 0) {
  228.         glVertex3fv(array[p]);
  229.         i = LINE_STEP;
  230.         } 
  231.         i--;
  232.         p = (p+1) & POINTMASK;
  233.     }
  234.     glVertex3fv(array[index]);
  235.     glEnd();
  236. }
  237.  
  238. void redraw(void)
  239. {
  240.     unsigned long p;
  241.     
  242.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  243.  
  244.     if(hexflag)
  245.     draw_hexcube();
  246.  
  247.     glColor3f(1.0, 0.0, 0.0);
  248.     drawLines(rp, rv);
  249.     sphdraw(rv[rp]);
  250.  
  251.     glColor3f(0.0, 0.0, 1.0);
  252.     drawLines(bp, bv);
  253.     sphdraw(bv[bp]);
  254.     
  255.     glColor3f(0.0, 1.0, 0.0);
  256.     drawLines(gp, gv);
  257.     sphdraw(gv[gp]);
  258.  
  259.     glColor3f(1.0, 0.0, 1.0);
  260.     drawLines(yp, yv);
  261.     sphdraw(yv[yp]);
  262.  
  263.     glColor3f(0.0, 1.0, 1.0);
  264.     drawLines(mp, mv);
  265.     sphdraw(mv[mp]);
  266.  
  267.     glutSwapBuffers();
  268. }
  269.  
  270. void move_eye(void)
  271. {
  272.     /* first move the eye */
  273.     eyev[0] += gravity * (rv[rp][0] - eyex[0]);
  274.     eyev[1] += gravity * (rv[rp][1] - eyex[1]);
  275.     eyev[2] += gravity * (rv[rp][2] - eyex[2]);
  276.  
  277.     /* adjust position using new velocity */
  278.     eyex[0] += eyev[0] * dt;
  279.     eyex[1] += eyev[1] * dt;
  280.     eyex[2] += eyev[2] * dt;
  281.  
  282.     /* move the lookat point */
  283.     /* it catches up to the red point if it's moving slowly enough */
  284.     eyel[0] += LG * (rv[rp][0] - eyel[0]);
  285.     eyel[1] += LG * (rv[rp][1] - eyel[1]);
  286.     eyel[2] += LG * (rv[rp][2] - eyel[2]);
  287.  
  288.     /* change view */
  289.     gluLookAt(eyex[0], eyex[1], eyex[2], eyel[0], eyel[1], eyel[2],
  290.           0, 1, 0);
  291. }
  292.  
  293. void draw_hexcube(void)
  294. {
  295.  
  296.     a += da;
  297.     if(a >= 720.)        /* depends on slowest rotation factor */
  298.     a = 0.;
  299.  
  300.     /* draw hexplanes, without changing z-values */
  301.     glDepthMask(GL_FALSE); 
  302.     glDisable(GL_DEPTH_TEST);
  303.  
  304.     /* x-y plane */
  305.     glColor3f(0.2, 0.2, 0.6);
  306.     glPushMatrix();
  307.     glTranslatef(cubeoffx, cubeoffy, cubeoffz);
  308.     glScalef(CUBESCALE, CUBESCALE, CUBESCALE);
  309.     draw_hexplane();
  310.     glPopMatrix();
  311.  
  312.     /* x-y plane, translated */
  313.     glPushMatrix();
  314.     glTranslatef(cubeoffx, cubeoffy, cubeoffz - 2*CUBESIDE);
  315.     glScalef(CUBESCALE, CUBESCALE, CUBESCALE);
  316.     draw_hexplane();
  317.     glPopMatrix();
  318.  
  319.     glColor3f(0.6, 0.2, 0.2);
  320.     /* x-z plane, translate low */
  321.     glPushMatrix();
  322.     glRotatef(90, 1.0, 0.0, 0.0);
  323.     glTranslatef(cubeoffx, cubeoffz - CUBESIDE, -cubeoffy + CUBESIDE);
  324.     glScalef(CUBESCALE, CUBESCALE, CUBESCALE);
  325.     draw_hexplane();
  326.     glPopMatrix();
  327.  
  328.     /* x-z plane, translate high */
  329.     glPushMatrix();
  330.     glRotatef(90, 1.0, 0.0, 0.0);
  331.     glTranslatef(cubeoffx, cubeoffz - CUBESIDE, -cubeoffy - CUBESIDE);
  332.     glScalef(CUBESCALE, CUBESCALE, CUBESCALE);
  333.     draw_hexplane();
  334.     glPopMatrix();
  335.  
  336.     glColor3f(0.2, 0.6, 0.2);
  337.     /* y-z plane, translate low */
  338.     glPushMatrix();
  339.     glRotatef(90, 0.0, 1.0, 0.0);
  340.     glTranslatef(-cubeoffz + CUBESIDE, cubeoffy, cubeoffx + CUBESIDE);
  341.     glScalef(CUBESCALE, CUBESCALE, CUBESCALE);
  342.     draw_hexplane();
  343.     glPopMatrix();
  344.     
  345.     /* y-z plane, translate high */
  346.     glPushMatrix();
  347.     glRotatef (90, 0.0, 1.0, 0.0);
  348.     glTranslatef(-cubeoffz + CUBESIDE, cubeoffy, cubeoffx - CUBESIDE);
  349.     glScalef(CUBESCALE, CUBESCALE, CUBESCALE);
  350.     draw_hexplane();
  351.     glPopMatrix();
  352.  
  353.     glFlush();
  354.     glDepthMask(GL_TRUE);
  355.     glEnable(GL_DEPTH_TEST);
  356. }
  357.  
  358. float hex_data[8][3] =  {
  359.     {0., 0., 0.},
  360.     {1.155, 0., 0.},
  361.     {0.577, 1., 0.},
  362.     {-0.577, 1., 0.},
  363.     {-1.155, 0., 0.},
  364.     {-0.577, -1., 0.},
  365.     {0.577, -1., 0.},
  366.     {1.155, 0., 0.},
  367. };
  368.  
  369. /* draws a hexagon 2 units across, in the x-y plane, */
  370. /* centered at <0, 0, 0> */
  371.  
  372. void draw_hexagon(void)
  373. {
  374.     if(wflag) {
  375.     glPushMatrix();
  376.     glRotatef(a, 0.0, 0.0, 1.0);
  377.     }
  378.  
  379.     glBegin(GL_TRIANGLE_FAN);
  380.     glVertex3fv(hex_data[0]);
  381.     glVertex3fv(hex_data[1]);
  382.     glVertex3fv(hex_data[2]);
  383.     glVertex3fv(hex_data[3]);
  384.     glVertex3fv(hex_data[4]);
  385.     glVertex3fv(hex_data[5]);
  386.     glVertex3fv(hex_data[6]);
  387.     glVertex3fv(hex_data[7]);
  388.     glEnd();
  389.  
  390.     if(wflag)
  391.     glPopMatrix();
  392. }
  393.  
  394. void tmp_draw_hexplane(void)
  395. {
  396.     glRectf(-2.0, -2.0, 2.0, 2.0);
  397. }
  398.  
  399. /* draw 7 hexagons */
  400. void draw_hexplane(void)
  401. {
  402.     if(wflag) {
  403.     glPushMatrix();
  404.     glRotatef(-0.5*a, 0.0, 0.0, 1.0);
  405.     }
  406.  
  407.     /* center , <0, 0, 0> */
  408.     draw_hexagon();
  409.  
  410.     /* 12 o'clock, <0, 4, 0> */
  411.     glTranslatef(0., 4., 0.);
  412.     draw_hexagon();
  413.  
  414.     /* 10 o'clock, <-3.464, 2, 0> */
  415.     glTranslatef(-3.464, -2., 0.);
  416.     draw_hexagon();
  417.  
  418.     /* 8 o'clock, <-3.464, -2, 0> */
  419.     glTranslatef(0., -4., 0.);
  420.     draw_hexagon();
  421.  
  422.     /* 6 o'clock, <0, -4, 0> */
  423.     glTranslatef(3.464, -2., 0.);
  424.     draw_hexagon();
  425.  
  426.     /* 4 o'clock, <3.464, -2, 0> */
  427.     glTranslatef(3.464, 2., 0.);
  428.     draw_hexagon();
  429.  
  430.     /* 2 o'clock, <3.464, 2, 0> */
  431.     glTranslatef(0., 4., 0.);
  432.     draw_hexagon();
  433.  
  434.     if(wflag)
  435.     glPopMatrix();
  436. }
  437.  
  438. void sphdraw(float args[3])
  439. {
  440.     glPushMatrix();
  441.     glTranslatef(args[0], args[1], args[2]);
  442.     glCallList(asphere);
  443.     glPopMatrix();
  444. }
  445.  
  446. void setPerspective(int angle, float aspect, float zNear, float zFar)
  447. {
  448.     glPushAttrib(GL_TRANSFORM_BIT);
  449.     glMatrixMode(GL_PROJECTION);
  450.     gluPerspective(angle * 0.1, aspect, zNear, zFar);
  451.     glPopAttrib();
  452. }
  453.  
  454. /* initialize global 3-vectors */
  455. void init_3d(void)
  456. {
  457.     (void)srand48((long)time((time_t*)NULL));
  458.  
  459.     /* initialize colored points */
  460.     rv[0][0] = (float)drand48() * 10.;
  461.     rv[0][1] = (float)drand48() * 10.;
  462.     rv[0][2] = (float)drand48() * 10. - 10.;
  463.  
  464.     bv[0][0] = rv[0][0] + (float)drand48()*5.;
  465.     bv[0][1] = rv[0][1] + (float)drand48()*5.;
  466.     bv[0][0] = rv[0][2] + (float)drand48()*5.;
  467.  
  468.     gv[0][0] = rv[0][0] + (float)drand48()*5.;
  469.     gv[0][1] = rv[0][1] + (float)drand48()*5.;
  470.     gv[0][0] = rv[0][2] + (float)drand48()*5.;
  471.  
  472.     yv[0][0] = rv[0][0] + (float)drand48()*5.;
  473.     yv[0][1] = rv[0][1] + (float)drand48()*5.;
  474.     yv[0][0] = rv[0][2] + (float)drand48()*5.;
  475.  
  476.     mv[0][0] = rv[0][0] + (float)drand48()*5.;
  477.     mv[0][1] = rv[0][1] + (float)drand48()*5.;
  478.     mv[0][0] = rv[0][2] + (float)drand48()*5.;
  479.  
  480.     /* initialize eye velocity */
  481.     eyev[0] = eyev[1] = eyev[2] = 0.;
  482. }
  483.  
  484.  
  485. void init_graphics(void)
  486. {
  487.     int width = 600;
  488.     int height = 600;
  489.  
  490.     xmax = width;
  491.     ymax = height;
  492.     glDrawBuffer(GL_BACK);
  493.     glEnable(GL_DEPTH_TEST);
  494.     glClearColor(0.0, 0.0, 0.0, 0.0);
  495.     glClearDepth(1.0);
  496.  
  497.     glEnable(GL_CULL_FACE);
  498.     glCullFace(GL_BACK);
  499.  
  500.     glViewport(0, 0, xmax, ymax);
  501.     setPerspective(fovy, (float)xmax/(float)ymax, 0.01, farplane);
  502.     quadObj = gluNewQuadric();
  503.     gluQuadricNormals(quadObj, GLU_NONE);
  504.     asphere = glGenLists(1);
  505.     glNewList(asphere, GL_COMPILE);
  506.     gluSphere(quadObj, 0.3, 12, 8);
  507.     glEndList();
  508. }
  509.  
  510. extern char *optarg;
  511. extern int optind, opterr;
  512.  
  513. #define USAGE "usage message: this space for rent\n"
  514. void parse_args(int argc, char **argv)
  515. {
  516.     int c;
  517.  
  518.     hexflag = sflag = fflag = wflag = gflag = debug = FALSE;
  519.     opterr = 0;
  520.  
  521.     while( (c = getopt(argc, argv, "Xhixs:f:w:g:")) != -1)
  522.     switch(c) {
  523.       case 'X':
  524.         debug = TRUE;
  525.         break;
  526.       case 'h':
  527.         print_usage(argv[0]);
  528.         exit(1);    
  529.       case 'i':
  530.         print_info();
  531.         exit(1);    
  532.       case 'x':
  533.         hexflag = TRUE;
  534.         farplane = 300.;
  535.         break;
  536.       case 's':
  537.         sflag = TRUE;
  538.         speed = atoi(optarg);
  539.         if(speed < 0) {
  540.         fprintf(stderr, "Use a small positive value for speed ('s').\n");
  541.         fprintf(stderr, "Try %s -h for help\n", argv[0]);
  542.         exit(1);
  543.         }
  544.         break;
  545.       case 'f':
  546.         fflag = TRUE;
  547.         frame = atoi(optarg);
  548.         if(frame < 0) {
  549.         fprintf(stderr, "Try a small positive value for \n");
  550.         fprintf(stderr, "'f'; this is the number of vertical ");
  551.         fprintf(stderr, "retraces per redraw\n");
  552.         fprintf(stderr, "Try %s -h for help\n", argv[0]);
  553.         exit(1);
  554.         }
  555.         break;
  556.       case 'w':
  557.         wflag = TRUE;
  558.         da = atof(optarg);
  559.         if(da > 10.) {
  560.         fprintf(stderr, "That's a large rotational velocity ('w')");
  561.         fprintf(stderr, " but you asked for it\n");
  562.         }
  563.         break;
  564.       case 'g':
  565.         gflag = TRUE;
  566.         gravity = atof(optarg);
  567.         if(gravity <= 0) {
  568.         fprintf(stderr, "Gravity ('g') should be positive\n");
  569.         fprintf(stderr, "Try %s -h for help\n", argv[0]);
  570.         }
  571.         break;
  572.       case '?':
  573.         fprintf(stderr, USAGE);
  574.     }
  575.  
  576.     /* set up default values */
  577.     if(!sflag)
  578.     speed = 3;
  579.     if(!fflag)
  580.     frame = 2;    
  581.     if(!wflag)
  582.     da = 0.;
  583.     if(!gflag)
  584.     gravity = G;
  585. }
  586.  
  587. void print_usage(char *program)
  588. {
  589. printf("\nUsage: %s [-h] [-i] [-x] [-s speed]", program);
  590. printf(" [-w rot_v] [-g gravity]\n\n");
  591. printf("-h              Print this message.\n");
  592. printf("-i              Print information about the demo.\n");
  593. printf("-x              Enclose the particles in a box made of hexagons.\n");
  594. printf("-s speed        Sets the number of new line segments per redraw \n");
  595. printf("                interval per line. Default value: 3.\n");
  596.  
  597. /*** The X port does not currently include a timer, so this feature is disabled.
  598. printf("-f framenoise   Sets the number of vertical retraces per redraw\n");
  599. printf("                interval. Example: -f 2 specifies one redraw per\n");
  600. printf("                2 vertical retraces, or 30 frames per second.\n");
  601. printf("                Default value: 2.\n");
  602. ************/
  603.  
  604. printf("-w rot_v        Spins the hexagons on their centers, and the sides\n");
  605. printf("                of the box on their centers. Hexagons spin at the\n");
  606. printf("                rate rot_v degrees per redraw, and box sides spin\n");
  607. printf("                at -rot_v/2 degrees per redraw.\n");
  608. printf("-g gravity      Sets the strength of the attraction of the eye to\n");
  609. printf("                the red particle. Actually, it's not gravity since\n");
  610. printf("                the attraction is proportionate to distance.\n");
  611. printf("                Default value: 0.002. Try large values!\n");
  612. /* input added for GLX port */
  613. printf(" Executions control:  \n");
  614. printf("    <spacebar>    step through single frames\n");
  615. printf("    g        begin continuous frames\n");
  616. printf("    s        stop continuous frames\n");
  617.  
  618. }
  619.  
  620. void print_info(void)
  621. {
  622. printf("\nLORENZ ATTRACTOR DEMO\n\n");
  623. printf("This program shows some particles stuck in a Lorenz attractor (the \n");
  624. printf("parameters used are r=28, b=8/3, sigma=10). The eye is attracted to \n");
  625. printf("the red particle, with a force directly proportional to distance. \n");
  626. printf("A command line argument puts the particles inside a box made of hexagons, \n");
  627. printf("helping  to maintain the sense of 3 dimensions, but it can slow things down.\n");
  628. printf("Other options allow you to play with the redraw rate and gravity.\n\n");
  629.  
  630. printf("Try lorenz -h for the usage message.\n");
  631. }
  632.